// Copyright (c) 2009 http://grommet.codeplex.com
// This source is subject to the Microsoft Public License.
// See http://www.opensource.org/licenses/ms-pl.html
// All other rights reserved.

using System;
using Microsoft.SPOT;
using System.Net.Sockets;
using System.Net;
using Microsoft.SPOT.Hardware;
using System.Text;
using System.Ext;
using System.IO;
using Grommet.Ext;

namespace System.Net
{
    public class HttpWebRequest : WebRequest
    {
        private HttpWebResponse response;
        private MemoryStream requestStream;
        private long contentLength;

        public override WebHeaderCollection Headers { get; set; }
        public override Uri RequestUri { get; protected set; }
        public override long ContentLength 
        {
            get
            {
                return contentLength;
            }
            set
            {
                if (response != null)
                {
                    throw new InvalidOperationException("Request already submitted.");
                }
                if (value < 0L)
                {
                    throw new ArgumentOutOfRangeException();
                }
                contentLength = value;
            } 
        }
        public override string ContentType { get; set; }
        public override string Method { get; set; }
        public override int Timeout { get; set; }
        public string UserAgent { get; set; }

        internal HttpWebRequest(Uri requestUri)
        {
            this.RequestUri = requestUri;
            Method = "GET";
            Headers = new WebHeaderCollection();
            response = null;
            requestStream = new MemoryStream();
            contentLength = -1;
        }

        public override WebResponse GetResponse()
        {
            IPHostEntry host = Dns.GetHostEntry(RequestUri.Host);
            if (host.AddressList.Length == 0)
            {
                throw new WebException(WebExceptionStatus.NameResolutionFailure, null);
            }
            
            int index = 0;
            while (index < host.AddressList.Length && host.AddressList[index] == null)
            {
                index++;
            }
            if (index == host.AddressList.Length)
            {
                throw new WebException(WebExceptionStatus.NameResolutionFailure, null);
            }

            IPEndPoint endpoint = new IPEndPoint(host.AddressList[index], RequestUri.Port);

            using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
            {
                if (response == null)
                {
                    socket.SendTimeout = Timeout;
                    socket.ReceiveTimeout = Timeout;
                    socket.Connect(endpoint);

                    if (contentLength < 0L)
                    {
                        contentLength = requestStream.Length;
                    }

                    MemoryStream testStream = new MemoryStream();


                    using (NetworkStream netStream = new NetworkStream(socket))
                    using (StreamWriter writer = new StreamWriter(netStream))
                    using (StreamReader reader = new StreamReader(netStream))
                    {

                        // Send Request
                        writer.WriteLine(string.Concat(Method, " ", RequestUri.AbsolutePath, " HTTP/1.1"));
                        writer.Write("Host: ");
                        writer.WriteLine(RequestUri.Host);
                        if (!UserAgent.IsNullOrEmpty())
                        {
                            writer.Write("User-Agent: ");
                            writer.WriteLine(UserAgent);
                        }
                        if (!ContentType.IsNullOrEmpty())
                        {
                            writer.Write("Content-Type: ");
                            writer.WriteLine(ContentType);
                        }
                        if (ContentLength != -1)
                        {
                            writer.Write("Content-Length: ");
                            writer.WriteLine(ContentLength);
                        }
                        for (int i = 0; i < Headers.Count; i++)
                        {
                            writer.WriteLine(string.Concat(Headers.Keys[i], ": ", Headers[i]));
                        }
                        writer.WriteLine();
                        writer.Flush();

                        requestStream.Seek(0L, SeekOrigin.Begin);
                        requestStream.WriteTo(netStream);
                        //requestStream.Flush();
                        //writer.Write(requestStream.ToArray());
                        writer.WriteLine();
                        writer.Flush();

                        // Receive response
                        response = new HttpWebResponse(RequestUri);
                        response.ReadStream(reader);
                    }

                    return response;
                }
            }
            return base.GetResponse();
        }

        public override System.IO.Stream GetRequestStream()
        {
            return requestStream;
        }

        private byte[] StringToArray(string value)
        {
            return Encoding.UTF8.GetBytes(value);
        }
    }
}
